#ifndef ODBC_ODBC_ERROR_HPP
#define ODBC_ODBC_ERROR_HPP

/// \ingroup OdbcLibrary
/// \file odbc_error.hpp
/// It contains the ODBC specific error related classes.

#include "odbc/odbc_config.hpp"
#include "odbc/details/os_sql_wrapper.hpp"
#include <stdexcept>
#include <string>
#include <list>

namespace odbc
{

class statement;
class environment;
class connection;

#ifdef _MSC_VER
#pragma warning( push)
#pragma warning( disable: 4251)
#endif

/// \ingroup OdbcLibrary
/// \brief It provides an information part regarding an ODBC specific error.
class ODBC_DECL diagnostic_record
{
public:
	///	\brief It initializes the diagnostic record with the description information.
	/// \param sqlState the five-character \c SQLSTATE code pertaining to the diagnostic record RecNumber. The first two 
	///		characters indicate the class; the next three indicate the subclass.
	/// \param nativeError the native error code, specific to the data source.
	/// \param errorMessage the diagnostic message text string.
	/// \test The initialization of the diagnostic record.
	diagnostic_record( const std::string& sqlState, int nativeError, const std::string& errorMessage);

	/// \brief It gets the sql state of this diagnostic record.
	const std::string& sql_state() const 
	{ 
		return sqlState_; 
	}

	/// \brief It gets the error message of this diagnostic record.
	const std::string& error_message() const 
	{ 
		return  errorMessage_; 
	}

	///	\brief It gets the native error code of this diagnostic record.
	int native_error() const 
	{ 
		return nativeError_; 
	}

private:
	/// \internal
	///	\brief It contains the sql state.
	const std::string sqlState_;

	/// \internal
	/// \brief It contains the native error code.
	const int nativeError_;

	/// \internal
	/// \brief It contains the error message.
	const std::string errorMessage_;


private:
	diagnostic_record& operator=( const diagnostic_record& );
};

#ifdef _MSC_VER
#pragma warning( pop)
#endif


#ifdef _MSC_VER
#pragma warning( push)
#pragma warning( disable: 4251 4275)
#endif

/// \ingroup OdbcLibrary
/// \brief This is an exception that can be generated by the calls to ODBC API 
/// functions. When an ODBC function call returns an error, this exception 
/// is constructed and thrown for further catch.
class ODBC_DECL odbc_error: public std::runtime_error
{
	typedef std::list< diagnostic_record> diag_rec_collection;
public:
	/// \brief It initializes the error object, by setting the ODBC error code.
	/// \param resultErrorCode the occurred ODBC error code.
	/// \param statement the statement object that provoked the error.
	odbc_error( SQLRETURN resultErrorCode, const statement& statement);

	/// \brief It initializes the error object, by setting the ODBC error code.
	/// \param resultErrorCode the occurred ODBC error code.
	/// \param environment the environment object that provoked the error.
	odbc_error( SQLRETURN resultErrorCode, const environment& environment);

	/// \brief It initializes the error object, by setting the ODBC error code.
	/// \param resultErrorCode the occurred ODBC error code.
	/// \param connection the connection object that provoked the error.
	odbc_error( SQLRETURN resultErrorCode, const connection& connection);

	/// \brief It retrieves the ODBC error code.
	/// \return the ODBC error code.
	SQLRETURN code() const { return resultErrorCode_; }

	///	\brief It gets the error message, including the ODBC error diagnostics.
	virtual const char* what() const throw();

	/// \brief It is an utility method, that checks the specified result from an ODBC API function and throws an 
	///		\c odbc_error if the result is not a success code.
	/// \param result the resultCode code provided by an ODBC API function call.
	/// \param stat the statement object that generated the result code.
	/// \exception odbc_error thrown if the result code indicates an error.
	static void check_success( SQLRETURN resultCode, const statement& stat);

	/// \brief It is an utility method, that checks the specified result from an ODBC API function and throws an 
	///		\c odbc_error if the result is not a success code.
	/// \param result the resultCode code provided by an ODBC API function call.
	/// \param env the environment object that generated the result code.
	/// \exception odbc_error thrown if the result code indicates an error.
	static void check_success( SQLRETURN resultCode, const environment& env);

	/// \brief It is an utility method, that checks the specified result from an ODBC API function and throws an 
	///		\c odbc_error if the result is not a success code.
	/// \param resultCode the result code provided by an ODBC API function call.
	/// \param conn the statement object that generated the result code.
	/// \exception odbc_error thrown if the result code indicates an error.
	static void check_success( SQLRETURN resultCode, const connection& conn);

private:
	/// \brief Contains the error code returned by an ODBC API function call.
	SQLRETURN resultErrorCode_;

	/// \brief It contains the collection of diagnostic records corresponding to the ODBC error.
	diag_rec_collection diagnostics_;

	/// \brief It contains the error message.
	std::string errorMessage_;

	///	\brief It gets the diagnostic records for this error.
	/// \param handle the handle of the ODBC entity that provoked the error.
	void fetch_diagnostics( SQLHANDLE handle, SQLSMALLINT handleType);

	///	\brief It transforms the collection of diagnostic records into its string representation and puts it into the 
	///		\c errorMessage_ member.
	void build_error_message();
};

#ifdef _MSC_VER
#pragma warning( pop)
#endif

} // namespace odbc

#endif ODBC_ODBC_ERROR_HPP
